home *** CD-ROM | disk | FTP | other *** search
- /*
- * (c)Copyright 1992-1997 Obvious Implementations Corp. Redistribution and
- * use is allowed under the terms of the DICE-LICENSE FILE,
- * DICE-LICENSE.TXT.
- */
-
- /*
- * CEXP.C
- *
- */
-
- #include "defs.h"
-
- Prototype long ParseIfExp(char *, short *, long, short);
- Prototype void PushOp(short, short, short);
- Prototype int TopOfOpStack(void);
- Prototype int SecondOffOpStack(void);
- Prototype void PushAtom(long, short);
-
- Local int CombineOp(void);
- Local int GetAtomStack(short *, long *);
- Local int ParseCharConst(char *, long, long, long *);
- Local int ParseInt(char *, long, long, long *);
- Local int HexDig(char);
- Local int OctDig(char);
-
- #define MAXATOM 128
- #define MAXOPER 128
-
- #define CGTEQ 256
- #define CGTGT 257
- #define CLTEQ 258
- #define CLTLT 259
- #define CNOTEQ 260
- #define CEQEQ 261
- #define CSYM 262
- #define CUMI 263
-
- #define CDEFINED 264
- #define CANDAND 265
- #define COROR 266
-
- #define QBIN 4 /* binary operator, else unary */
- #define LR 1 /* left to right, else */
- #define RL 2 /* right to left */
- #define BLR (LR|QBIN)
- #define BRL (RL|QBIN)
- #define XX 0
-
- typedef struct Atom {
- long Value;
- short Undef;
- short Reserved;
- } Atom;
-
- typedef struct Oper {
- short Token;
- short Pri;
- short Type;
- short Reserved;
- } Oper;
-
- static Atom AtomStack[MAXATOM];
- static Oper OperStack[MAXOPER];
- static short AtomIdx;
- static short OperIdx;
- static short BaseAtomIdx;
- static short BaseOperIdx;
-
- long
- ParseIfExp(char *buf, short *pundef, long max, short subsym)
- {
- short unary = 1;
- short i = 0;
- short parens = 0;
- short baseOperIdx;
- short baseAtomIdx;
-
- baseOperIdx = BaseOperIdx = OperIdx;
- baseAtomIdx = BaseAtomIdx = AtomIdx;
-
- while (i < max) {
- short c = buf[i];
-
- ++i;
- if (c == ' ' || c == 9 || c == '\n')
- continue;
-
- if (unary) { /* int, sym, !exp, ~exp (exp) */
- switch(c) {
- case '!':
- case '~':
- PushOp(c, 140, RL);
- break;
- case '-':
- PushOp(CUMI, 140, RL);
- break;
- case '(':
- ++parens;
- PushOp(c, 0, XX);
- break;
- default:
- if (c >= '0' && c <= '9') {
- long v;
- /*
- printf("%d(%c) ", i - 1, buf[i-1]);
- */
- i = ParseInt(buf, i - 1, max, &v);
- /*
- printf("%d INT %d\n", i, v);
- */
- PushAtom(v, 0);
- unary = 0;
-
- break;
- }
- /*
- * NOTE, handles 'defined' by pushing unary op instead
- * of atom.
- */
- if (SymbolChar[c]) { /* SymbolChar[] includes '0'-'9' */
- short ni;
-
- --i;
- ni = ExtSymbol(buf, i, max);
- if (ni - i == 7 && strncmp(buf + i, "defined", 7) == 0) {
- PushOp(CDEFINED, 140, RL);
- } else if (TopOfOpStack() == CDEFINED || SecondOffOpStack() == CDEFINED) {
- Sym *sym = FindSymbol(buf + i, ni - i);
- if (sym)
- PushAtom(1, 0);
- else
- PushAtom(0, 1);
- unary = 0;
- } else {
- Sym *sym = FindSymbol(buf + i, ni - i);
-
- if (sym) {
- short xundef;
- long v;
- if (subsym == 0) {
- v = 0;
- xundef = 0;
- } else {
- /* We need to actually parse the symbol and then */
- /* evaluate any arguments. This code closely */
- /* mimics the code found in HandleSymbol, but it */
- /* has the additional requirement of not actually */
- /* sending anything out to the output file. */
- short oldType = sym->Type;
- short creType = 0;
-
- {
- long it = ni;
- /* The -max is so that we can flag to the */
- /* routine to not output anything */
- if (PrepareSymbolArgs(sym, buf, &it, -max) == NULL)
- goto syntax;
- ni = it;
- }
- /*
- * If pushing a macro argument for replace we must
- * enable the macro it came from. This allows
- * MAX(MAX(1,2),3) while disallowing loop conditions,
- * i.e. #define BAR(x) BAR(1,x)
- */
-
- if (sym->Type & SF_MACROARG) {
- if (sym->Creator == NULL)
- cerror(EFATAL_SOFTWARE_ERROR_CREATOR);
- creType = sym->Creator->Type;
- sym->Creator->Type &= ~SF_RECURSE;
- }
-
- v = ParseIfExp(sym->Text, &xundef, sym->TextLen, 1);
-
- if (sym->Type & SF_MACROARG)
- sym->Creator->Type = creType;
-
- if (sym->NumArgs >= 0)
- { /* undef symbol args symbols */
- short j;
- for (j = 0; j < sym->NumArgs; ++j)
- {
- if (UndefSymbol(sym->Args[j], sym->ArgsLen[j]) == 0)
- cerror(EFATAL_SOFTWARE_ERROR_MACRO,
- sym->SymName, sym->Args[j]);
- }
- }
- sym->Type = oldType;
-
- BaseOperIdx = baseOperIdx;
- BaseAtomIdx = baseAtomIdx;
- }
- PushAtom(v, xundef);
- } else {
- PushAtom(0, 1);
- }
- unary = 0;
- }
- i = ni;
- break;
- }
- if (c == '\'') {
- long v;
- i = ParseCharConst(buf, i - 1, max, &v);
- PushAtom(v, 0);
- unary = 0;
- break;
- }
- syntax:
- cerror(EERROR_SYNTAX_ERROR);
- syntax2:
- *pundef = 1;
- AtomIdx = baseAtomIdx;
- OperIdx = baseOperIdx;
- return(0);
- }
- } else { /* + - * / % & | ^ <= << < == != > >> >= */
- unary = 1;
-
- switch(c) {
- case '+':
- case '-':
- PushOp(c, 120, BLR);
- break;
- case '*':
- case '/':
- case '%':
- PushOp(c, 130, BLR);
- break;
- case '&':
- if (i < max && buf[i] == '&') {
- PushOp(CANDAND, 50, BLR);
- ++i;
- } else {
- PushOp(c, 60, BLR);
- }
- break;
- case '^':
- PushOp(c, 70, BLR);
- break;
- case '|':
- if (i < max && buf[i] == '|') {
- ++i;
- PushOp(COROR, 40, BLR);
- } else {
- PushOp(c, 80, BLR);
- }
- break;
- case '<':
- if (i < max) {
- short d = buf[i];
- if (d == '<') {
- PushOp(CLTLT, 110, BLR);
- ++i;
- break;
- }
- if (d == '=') {
- PushOp(CLTEQ, 100, BLR);
- ++i;
- break;
- }
- }
- PushOp(c, 100, BLR);
- break;
- case '=':
- if (i >= max || buf[i] != '=')
- goto syntax;
- PushOp(CEQEQ, 90, BLR);
- ++i;
- break;
- case '!':
- if (i >= max || buf[i] != '=')
- goto syntax;
- PushOp(CNOTEQ, 90, BLR);
- ++i;
- break;
- case '>':
- if (i < max) {
- short d = buf[i];
- if (d == '>') {
- PushOp(CGTGT, 110, BLR);
- ++i;
- break;
- }
- if (d == '=') {
- PushOp(CGTEQ, 100, BLR);
- ++i;
- break;
- }
- }
- PushOp(c, 100, BLR);
- break;
- case ')':
- unary = 0;
- if (parens == 0) {
- cerror(EERROR_TOO_MANY_CLOSE_PARENS);
- goto syntax2;
- }
- --parens;
- while ((c = TopOfOpStack()) && c != '(')
- CombineOp();
- if (c == 0)
- goto syntax;
- CombineOp();
- break;
- default:
- goto syntax;
- }
- }
- }
- while (TopOfOpStack() >= 0 && CombineOp() >= 0);
-
- if (TopOfOpStack() >= 0)
- goto syntax;
-
- {
- long v;
-
- if (GetAtomStack(pundef, &v) < 0)
- goto syntax;
- if (GetAtomStack(NULL, NULL) >= 0) /* shouldn't be anything left */
- goto syntax;
- AtomIdx = baseAtomIdx;
- OperIdx = baseOperIdx;
- dbprintf(("RESULT %ld %d\n", v, *pundef));
- return(v);
- }
- }
-
- void
- PushOp(short token, short pri, short type)
- {
- if (pri) {
- while (OperIdx > BaseOperIdx) {
- Oper *op = OperStack + OperIdx - 1;
- if (pri > op->Pri)
- break;
- if (pri == op->Pri && (type & RL))
- break;
- if (CombineOp() < 0) {
- cerror(EERROR_SYNTAX_ERROR);
- break;
- }
- }
- }
- if (OperIdx == MAXOPER) {
- cerror(EERROR_EXPRESSION_TOO_COMPLEX);
- return;
- }
- {
- Oper *op = OperStack + OperIdx++;
-
- op->Pri = pri;
- op->Token = token;
- op->Type = type;
- }
- }
-
- int
- TopOfOpStack()
- {
- if (OperIdx <= BaseOperIdx)
- return(-1);
- return((int)OperStack[OperIdx-1].Token);
- }
-
- int
- SecondOffOpStack()
- {
- if (OperIdx - 1 <= BaseOperIdx)
- return(-1);
- return((int)OperStack[OperIdx-2].Token);
- }
-
-
- void
- PushAtom(long val, short isundef)
- {
- Atom *atom;
-
- if (AtomIdx == MAXATOM) {
- cerror(EERROR_EXPRESSION_TOO_COMPLEX);
- return;
- }
- atom = AtomStack + AtomIdx++;
- atom->Value = val;
- atom->Undef = isundef;
- }
-
- int
- CombineOp()
- {
- Oper *op;
- Atom *a1, *a2;
- Atom ar;
-
- if (OperIdx <= BaseOperIdx)
- return(-1);
- op = OperStack + --OperIdx;
-
- if (AtomIdx <= BaseAtomIdx)
- return(-1);
- a1 = AtomStack + --AtomIdx;
-
- if (op->Type & QBIN) {
- if (AtomIdx <= BaseAtomIdx)
- return(-1);
- a2 = AtomStack + --AtomIdx;
- }
-
- if (op->Type & QBIN) {
- ar.Undef = a1->Undef | a2->Undef;
-
- switch(op->Token) {
- case '+':
- ar.Value = a2->Value + a1->Value;
- break;
- case '-':
- ar.Value = a2->Value - a1->Value;
- break;
- case '*':
- ar.Value = a2->Value * a1->Value;
- break;
- case '/':
- if (a1->Value)
- ar.Value = a2->Value / a1->Value;
- else
- ar.Undef = 1;
- break;
- case '%':
- if (a1->Value)
- ar.Value = a2->Value % a1->Value;
- else
- ar.Undef = 1;
- break;
- case '&':
- ar.Value = a2->Value & a1->Value;
- break;
- case '|':
- ar.Value = a2->Value | a1->Value;
- break;
- case '^':
- ar.Value = a2->Value ^ a1->Value;
- break;
- case '<':
- ar.Value = a2->Value < a1->Value;
- break;
- case CLTLT:
- ar.Value = a2->Value << a1->Value;
- break;
- case CLTEQ:
- ar.Value = a2->Value <= a1->Value;
- break;
- case CEQEQ:
- ar.Value = a2->Value == a1->Value;
- break;
- case CNOTEQ:
- ar.Value = a2->Value != a1->Value;
- break;
- case '>':
- ar.Value = a2->Value > a1->Value;
- break;
- case CGTGT:
- ar.Value = a2->Value >> a1->Value;
- break;
- case CGTEQ:
- ar.Value = a2->Value >= a1->Value;
- break;
- case CANDAND:
- if (a2->Value && a1->Value)
- ar.Value = 1;
- else
- ar.Value = 0;
- break;
- case COROR:
- if (a2->Undef == 0 && a2->Value) {
- ar.Value = 1;
- ar.Undef = 0;
- } else if (a1->Undef == 0 && a1->Value) {
- ar.Value = 1;
- ar.Undef = 0;
- } else {
- ar.Value = 0;
- }
- break;
- default:
- cerror(EFATAL_ERROR_PARSING_EXP);
- break;
- }
- } else {
- ar.Undef = a1->Undef;
-
- switch(op->Token) {
- case '!':
- ar.Value = !a1->Value;
- break;
- case '~':
- ar.Value = ~a1->Value;
- break;
- case CUMI:
- ar.Value = -a1->Value;
- break;
- case '(':
- ar.Value = a1->Value;
- break;
- case CDEFINED:
- ar.Undef = 0;
- if (a1->Undef)
- ar.Value = 0;
- else
- ar.Value = 1;
- break;
- default:
- cerror(EFATAL_ERROR_PARSING_EXP);
- break;
- }
- }
- AtomStack[AtomIdx++] = ar;
- dbprintf(("op %c %03x result %ld (%d)\n", op->Token, op->Token, ar.Value, ar.Undef));
- return(0);
- }
-
- int
- GetAtomStack(pundef, pv)
- short *pundef;
- long *pv;
- {
- Atom *at;
-
- if (AtomIdx <= BaseAtomIdx) {
- if (pundef)
- *pundef = 1;
- return(-1);
- }
- at = AtomStack + --AtomIdx;
- if (pundef)
- *pundef = at->Undef;
- if (pv)
- *pv = at->Value;
- return(0);
- }
-
- int
- ParseCharConst(buf, i, max, pv)
- char *buf;
- long i;
- long max;
- long *pv;
- {
- ubyte c;
- long v = 0;
-
- if (buf[i] != '\'')
- return(0);
- ++i;
- while (i < max && (c = buf[i]) != '\'') {
- ++i;
- if (c == '\\' && i < max) {
- c = buf[i++];
- switch(c) {
- case 'a':
- c = 7;
- break;
- case 'b':
- c = 8;
- break;
- case 'f':
- c = 'f'&0x1F;
- break;
- case 'n':
- c = 10;
- break;
- case 'r':
- c = 13;
- break;
- case 't':
- c = 9;
- break;
- case 'v':
- c = 11;
- break;
- case 'x':
- {
- short n;
- short r = 0;
- short cnt = 2;
-
- while (cnt && (n = HexDig(c)) > 0) {
- r = (r << 4) + n;
- c = buf[i++];
- --cnt;
- }
- if (cnt)
- --i;
- c = r;
- }
- break;
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- {
- short cnt;
- short r;
- short n;
-
- for (r = cnt = 0; cnt < 3 && (n = OctDig(c)) >= 0; ++cnt) {
- r = (r << 3) + n;
- c = buf[i++];
- }
- --i;
- c = r;
- }
- break;
- default:
- c = buf[i];
- break;
- }
- }
- v = (v << 8) | c;
- }
- *pv = v;
- if (i < max) /* skip closing single quote */
- ++i;
- else
- cerror(EERROR_UNTERMINATED_CHARCONST);
- return(i);
- }
-
- /*
- * 0xhex
- * 0octal
- * 1-9decimal
- */
-
- int
- ParseInt(buf, i, max, pv)
- char *buf;
- long i;
- long max;
- long *pv;
- {
- char c;
- long v = 0;
-
- if (i < max && buf[i] == '0') {
- ++i;
- if (i < max && (buf[i] == 'x' || buf[i] == 'X')) { /* hex */
- short n;
- ++i;
- while (i < max && (n = HexDig(buf[i])) >= 0) {
- v = (v << 4) + n;
- ++i;
- }
- } else { /* oct */
- short n;
- while (i < max && (n = OctDig(buf[i])) >= 0) {
- v = (v << 3) + n;
- ++i;
- }
- }
- } else {
- while (i < max && (c = buf[i]) >= '0' && c <= '9') { /* dec */
- v = v * 10 + c - '0';
- ++i;
- }
- }
- while ((c = buf[i]) == 'L' || c == 'l' || c == 'U' || c == 'u')
- ++i;
- *pv = v;
- return(i);
- }
-
- int
- HexDig(char c)
- {
- if (c >= '0' && c <= '9')
- return (c - '0');
- if (c >= 'a' && c <= 'f')
- c = c + ('A' - 'a');
- if (c >= 'A' && c <= 'F')
- return (c + (10 - 'A'));
- return(-1);
- }
-
- int
- OctDig(char c)
- {
- if (c >= '0' && c <= '7')
- return (c - '0');
- return(-1);
- }
-
-